/*
    jME Task Framework, for executing tasks in a Java/OpenGL enviroment
    Copyright (C) 2005-2006,  Tijl Houtbeckers
    
    **** LICENSE: ****

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation,
	version 2.1.
	
	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

	**** CONTACT: ****

    I can be reached through the jmonkeyengine.com forums (user "llama"), 
    or the jmonkeyengine.com contact page:
    jmonkeyengine.com/index.php?option=com_contact&task=view&contact_id=5           

*/

/**
 * @author Tijl Houtbeckers
 */

package org.llama.jmex.task;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;

import com.jme.util.Timer;

public class TaskManager {

	private Task[] tasks;
	private int tasklimit;
	Timer timer;
	private HashSet identifiers = new HashSet();
	private TreeSet currenttasks = new TreeSet();
	
	public TaskManager(Timer timer) {
		tasks = new Task[10];
		if (timer == null)
			this.timer = Timer.getTimer();
		else
			this.timer = timer;
	}
	
	public TaskManager() {
		this(null);
	}	
	
	public synchronized boolean containsTask(Object identifier) {
		return identifiers.contains(identifier);
	}
	
	public synchronized void addTask(Task task, TaskRunner taskrunner) {
		task.setManagerAndRunner(this, taskrunner);
		identifiers.add(task.identifier()); 
		if (tasklimit + 1 >= tasks.length) {
			Task[] temptasks = new Task[tasks.length * 2];
			System.arraycopy(tasks, 0, temptasks, 0, tasks.length);
			tasks = temptasks;
		}
		tasks[tasklimit] = task;
		tasklimit++;
	}
	
	public synchronized void sortTasks() {
		
		for (int k = 0; k < tasklimit; k++) {
			tasks[k].updatePriority();
		}
		Arrays.sort(tasks,0,tasklimit);
		
	}
	
//	Task task;
	
	float start, end;
	
	private void completedTask(Task task) {
		task.reset();
		synchronized(this) {
			identifiers.remove(task.identifier());
		}
	}
	
	private Object[] taskrunners = new TaskRunner[0];
	private ArrayList taskrunnerslist = new ArrayList();
	public synchronized void addTaskRunner(TaskRunner runner) {
		if (taskrunnerslist.add(runner))
			taskrunners =  taskrunnerslist.toArray();
	}
	
	public synchronized void removeTaskRunner(TaskRunner runner) {
		if (taskrunnerslist.remove(runner))
			taskrunners = taskrunnerslist.toArray();
	}

	
	public float timeLeft() {		
		return end - timer.getTimeInSeconds();
	}
	
	public void runTasks(float seconds) {
		runTasks(seconds, taskrunners);
	}
	
	public void runTasks(float seconds, Object[] runners) {
		start = timer.getTimeInSeconds();
		end = start + seconds;
		currenttasks.clear();
		for (int k = 0; k < runners.length; k++) {
			Task[] tasks = ((TaskRunner)runners[k]).getTasks();
			for (int i = 0; i < tasks.length; i++) {
				Task task = tasks[i];
				
				if (task!= null && task.isUsingManager(this)) {

					if (task.isCompleted()) {
						completedTask(task);
					}
					else if (task.isPaused()){
						task.prepareRun();
						currenttasks.add(tasks[i]);
					}
				}				
			}
		}
		
		for (int k = 0; k < runners.length; k++) {
			TaskRunner runner = (TaskRunner)runners[k];
			int tasksearch = tasklimit;
			int reserve = runner.reserveTask();
//			System.out.println(runner.getClass().toString()+ " "+ reserve);
//			System.out.print("\n"+runner.getClass()+" "+reserve);
			while (reserve != -1 && --tasksearch >= 0) {
//				System.out.print(tasksearch+"|");
				if (tasks[tasksearch].isUsingRunner(runner)) {
//					System.out.println("YES");
					Task task = tasks[tasksearch];
					tasks[tasksearch] = null;
					tasklimit--;
					for (int i = tasksearch; i < tasklimit; i++) {
						tasks[i] = tasks[i+1];
					}
					task.assign(reserve);
					task.prepareRun();
					currenttasks.add(task);
					reserve = runner.reserveTask();
					
//					
				}
				else {
				}
			}
			if (reserve != -1)
				runner.cancelReserveTask(reserve);
		}
			
		Iterator it = currenttasks.iterator();
		while (it.hasNext() && timeLeft() > 0) {
			Task task = (Task)it.next();
			task.resume();
		}
		
		it = currenttasks.iterator();
		while (it.hasNext()) {
			Task task = (Task)it.next();
			task.attemptPause();
		}
	}

}
